package com.duoqin.audiowaves;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.ScaleAnimation;
import android.widget.ImageView;

import com.duoqin.widget.R;

import java.util.ArrayList;

public class WaveformView extends ViewGroup {

    private static final String TAG = "ASR/WaveformView";
    private ArrayList<ShapeHolder> mShapeHolders = new ArrayList<ShapeHolder>();
    private ArrayList<Float> peakValueList = new ArrayList<Float>();

    private ScaleAnimationListener mListener;

    private static final int DELAY_TIME = 10;
    private static final int ANIM_DURATION = 120;

    private static final String KEY_HEAD_POSITION = "key_head_position";
    private static final String KEY_PEAKVALUE = "key_peak_value";

    private static final int MSGID_START_HEAD_ANIMATION = 100;
    private static final int MSGID_UPDATE_SHAPEHOLDER = 101;

    private static final float REDUCE_RADIO = 0.95f;

    private static final int SPACE_LENGTH = 7;
    private static final int RECT_WIDTH = 4;
    private static final int RECT_HEIGHT = 4;
    private float mSpaceLength;
    private float mRectWidth;
    private float mRectHeight;

    private float mContainerWidth;
    private float mContainerHeight;

    private int[] mMiddleShape;
    private boolean mIsAnimStart;

    private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            Bundle bundle = null;
            ShapeHolder shapeHolder = null;
            float peakValue = 0.0f;
            int viewIndex = 0;
            int backViewIndex = 0;
            switch (msg.what) {
                case MSGID_START_HEAD_ANIMATION:

                    if (peakValueList.isEmpty()) {
                        //peakValue = (mContainerHeight / 2) / mRectHeight;
                        peakValue = 1.0f;
                        peakValueList.add(peakValue);
                    } else {
                        peakValue = peakValueList.get(peakValueList.size() - 1);
                    }

                    if (mMiddleShape[0] == mMiddleShape[1]) {
                        viewIndex = mMiddleShape[1];
                        shapeHolder = mShapeHolders.get(viewIndex);
                        initViewAnimation(shapeHolder, peakValue);
                    } else {
                        viewIndex = mMiddleShape[1];
                        shapeHolder = mShapeHolders.get(viewIndex);
                        initViewAnimation(shapeHolder, peakValue);

                        backViewIndex = mMiddleShape[0];
                        shapeHolder = mShapeHolders.get(backViewIndex);
                        initViewAnimation(shapeHolder, peakValue);
                    }
                    break;

                case MSGID_UPDATE_SHAPEHOLDER:
                    shapeHolder = (ShapeHolder) msg.obj;
                    bundle = msg.getData();
                    peakValue = bundle.getFloat(KEY_PEAKVALUE, 1.0f);

                    viewIndex = shapeHolder.getViewIndex();
                    initViewAnimation(shapeHolder, peakValue);

                    backViewIndex = mMiddleShape[0] - (viewIndex - mMiddleShape[1]);
                    shapeHolder = mShapeHolders.get(backViewIndex);
                    initViewAnimation(shapeHolder, peakValue);
                    break;
                default:
                    break;
            }
        }
    };

    public WaveformView(Context context) {
        this(context, null);
    }

    public WaveformView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WaveformView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mMiddleShape = new int[2];
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mContainerWidth = MeasureSpec.getSize(widthMeasureSpec);
        mContainerHeight = MeasureSpec.getSize(heightMeasureSpec); // 88dp
        float density = getResources().getDisplayMetrics().density; // 0.75
        mSpaceLength = density * SPACE_LENGTH;
        mRectWidth = density * RECT_WIDTH;
        mRectHeight = density * RECT_HEIGHT;
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right,
            int bottom) {
        if (changed) {
            int viewIndex = 0;
            mShapeHolders.clear();
            float coordinateX = mSpaceLength / 2 + mRectWidth / 2;
            float coordinateY = mContainerHeight / 2;
            while (coordinateX + mRectWidth < mContainerWidth) {
                Drawable drawable = getResources().getDrawable(
                        R.drawable.roundrect);
                ShapeHolder shapeHolder = new ShapeHolder();
                ImageView imv = new ImageView(getContext());
                int widthMeasureSpec = MeasureSpec.makeMeasureSpec(
                        (int) mRectWidth, MeasureSpec.EXACTLY);
                int heightMeasureSpec = MeasureSpec.makeMeasureSpec(
                        (int) mRectWidth, MeasureSpec.EXACTLY);
                int l = (int) coordinateX;
                int t = (int) (coordinateY - mRectHeight / 2);
                int r = (int) (coordinateX + mRectWidth);
                int b = (int) (coordinateY + mRectHeight / 2);
                imv.measure(widthMeasureSpec, heightMeasureSpec);
                imv.layout(l, t, r, b);
                imv.setImageDrawable(drawable);
                shapeHolder.setView(imv);
                shapeHolder.setViewIndex(viewIndex);
                mShapeHolders.add(shapeHolder);
                addView(imv);
                coordinateX = coordinateX + mSpaceLength + mRectWidth;
                viewIndex++;
            }
        }
    }

    public void prepareAnimation() {
        mIsAnimStart = true;
        ImageView imv = null;
        peakValueList.clear();
        for (int i = 0; i < mShapeHolders.size(); i++) {
            imv = mShapeHolders.get(i).getView();
            imv.clearAnimation();
        }

        int remainder = mShapeHolders.size() % 2;
        int middle = mShapeHolders.size() / 2;
        mMiddleShape = new int[2];
        ShapeHolder shapeHolder = null;
        if (0 == remainder) {
            mMiddleShape[0] = middle - 1;
            mMiddleShape[1] = middle;
            shapeHolder = mShapeHolders.get(mMiddleShape[0]);
            shapeHolder.setReduceValue(1.0f);

            shapeHolder = mShapeHolders.get(mMiddleShape[1]);
            shapeHolder.setReduceValue(1.0f);
        } else {
            mMiddleShape[0] = middle;
            mMiddleShape[1] = middle;
            shapeHolder = mShapeHolders.get(mMiddleShape[0]);
            shapeHolder.setReduceValue(1.0f);
        }

        int turnLeft = mMiddleShape[0] - 1;
        int turnRight = mMiddleShape[1] + 1;
        float reduceRadio = REDUCE_RADIO;
        while (turnLeft >= 0) {
            shapeHolder = mShapeHolders.get(turnLeft);
            shapeHolder.setReduceValue(reduceRadio);
            reduceRadio *= REDUCE_RADIO;
            turnLeft--;
        }

        reduceRadio = REDUCE_RADIO;
        while (turnRight < mShapeHolders.size()) {
            shapeHolder = mShapeHolders.get(turnRight);
            shapeHolder.setReduceValue(reduceRadio);
            reduceRadio *= REDUCE_RADIO;
            turnRight++;
        }

        mHandler.removeMessages(MSGID_START_HEAD_ANIMATION);
        mHandler.sendEmptyMessage(MSGID_START_HEAD_ANIMATION);
    }

    private void initViewAnimation(ShapeHolder shapeHolder, float peakValue) {
        shapeHolder.setPeakValue(peakValue);
        float value = shapeHolder.getReduceValue() * peakValue;
        Animation scaleAnimation = new ScaleAnimation(1.0f, 1.0f, 1.0f, value,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                0.5f);
        scaleAnimation.setDuration(ANIM_DURATION);
        scaleAnimation.setRepeatCount(1);
        scaleAnimation.setRepeatMode(Animation.REVERSE);
        shapeHolder.setAnimation(scaleAnimation);
        int valueIndex = shapeHolder.getViewIndex();
        if (valueIndex >= mMiddleShape[1]) {
            mListener = new ScaleAnimationListener(shapeHolder);
            scaleAnimation.setAnimationListener(mListener);
        }
        shapeHolder.startAnimation();
    }

    public void updateWaveData(float value) {
        float peakValue = Math.max(1.0f, (mContainerHeight - mRectHeight) *
                value / mRectHeight);
        peakValueList.add(peakValue);
    }

    public void stopAnimation() {
        mIsAnimStart = false;
        mHandler.removeMessages(MSGID_START_HEAD_ANIMATION);
        mHandler.removeMessages(MSGID_UPDATE_SHAPEHOLDER);
    }

    class ScaleAnimationListener implements AnimationListener {

        private ShapeHolder shapeHolder;

        public ScaleAnimationListener(ShapeHolder shapeHolder) {
            this.shapeHolder = shapeHolder;
        }

        @Override
        public void onAnimationStart(Animation animation) {
            int viewIndex = shapeHolder.getViewIndex() + 1;
            if (viewIndex < mShapeHolders.size() && mIsAnimStart) {
                float peakValue = shapeHolder.getPeakValue();
                //Log.v(TAG, "start animation peakvalue:" + peakValue);
                ShapeHolder nextHolder = mShapeHolders.get(viewIndex);
                Message msg = Message.obtain();
                msg.what = MSGID_UPDATE_SHAPEHOLDER;
                Bundle bundle = new Bundle();
                bundle.putFloat(KEY_PEAKVALUE, peakValue);
                msg.setData(bundle);
                msg.obj = nextHolder;
                mHandler.sendMessage(msg);
            }
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            shapeHolder.getView().clearAnimation();
            int viewIndex = shapeHolder.getViewIndex();
            if (viewIndex == mMiddleShape[1] && mIsAnimStart) {
                //Log.i(TAG, "animation end " + viewIndex);
                Message msg = Message.obtain();
                msg.what = MSGID_START_HEAD_ANIMATION;
                msg.obj = mShapeHolders.get(viewIndex);
                Bundle data = new Bundle();
                data.putInt(KEY_HEAD_POSITION, viewIndex);
                msg.setData(data);
                mHandler.sendMessage(msg);
            }
        }

        @Override
        public void onAnimationRepeat(Animation animation) {

        }
    }
}

